import React, { useImperativeHandle, useRef, useEffect, useMemo } from 'react';
import PropTypes from 'prop-types';
import { useDynamicList } from '@/hooks';
import { Button, Empty, Form } from 'antd';
import IconPro from '@/components/IconPro';
import classNames from 'classnames';
import styles from './index.less';

// 表格头
const TableHeader = ({ columns }) => (
    <thead className={styles.tableHeader}>
        <tr>
            {columns
                ?.filter(item => !item.hide)
                ?.map(column => {
                    const { title, dataIndex, key, width, align = 'left' } = column;
                    return (
                        <th
                            key={key ?? dataIndex ?? title}
                            className={styles.tableHeaderTd}
                            style={{ width, textAlign: align }}
                        >
                            <span>{title}</span>
                        </th>
                    );
                })}
        </tr>
    </thead>
);

// 表格单元格
const TableCell = ({ fieldName, column, record, recordKey, index, form, methods, disabled, readonly }) => {
    const { dataIndex, render, component, rules, hide } = column;
    const text = record[dataIndex];
    const { getFieldDecorator } = form;
    const currentKey = `${fieldName}[${recordKey}]`;
    const fieldDecorator = (id, options) => child => (
        <Form.Item>
            {getFieldDecorator(`${currentKey}.${id}`, { validateTrigger: 'onChange', ...options })(child)}
        </Form.Item>
    );
    const getFieldValue = columnFieldName => form.getFieldValue(`${currentKey}.${columnFieldName}`);
    const setFieldValue = (columnFieldName, value) =>
        form.setFieldsValue({ [`${currentKey}.${columnFieldName}`]: value });
    const setFieldsValue = value => {
        const fields = Object.keys(value);
        const result = {};
        fields.forEach(field => {
            result[`${currentKey}.${field}`] = value[field];
        });
        return form.setFieldsValue(result);
    };
    if (!render && dataIndex) {
        getFieldDecorator(`${currentKey}.${dataIndex}`, { initialValue: record[dataIndex] });
    }

    const renderHidden = () =>
        getFieldDecorator(`${currentKey}.${dataIndex}`, { initialValue: text })(
            <input type="text" style={{ display: 'none' }} />
        );
    const renderComponent = () => {
        // 没有 render 就直接展示数据
        if (!hide && !render && !component && dataIndex) {
            return record[dataIndex];
        }
        // 有 render 就使用 render
        if (render) {
            return render({
                text,
                record,
                recordKey,
                index,
                fieldDecorator,
                getFieldValue,
                setFieldValue,
                setFieldsValue,
                form,
                methods,
                disabled,
                readonly
            });
        }
        if (!render && component) {
            return fieldDecorator(dataIndex, {
                initialValue: record[dataIndex],
                rules
            })(component);
        }
        return null;
    };

    return (
        <td className={styles.tableBodyTd} style={hide ? { display: 'none' } : null}>
            {renderHidden()}
            {!hide && <Form.Item>{renderComponent()}</Form.Item>}
        </td>
    );
};

// 表格行
const TableRow = ({ fieldName, columns, index, record, recordKey, form, methods, disabled, readonly }) => (
    <tr className={styles.tableBodyTr}>
        {columns.map(column => (
            <TableCell
                key={`${fieldName}-${recordKey}-${column.key ?? column.dataIndex}`}
                fieldName={fieldName}
                column={column}
                index={index}
                record={record}
                form={form}
                recordKey={recordKey}
                methods={methods}
                disabled={disabled}
                readonly={readonly}
            />
        ))}
    </tr>
);
/**
 * 基础模板
 * @param props
 * @returns {JSX.Element}
 * @constructor
 */
const DynamicTable = React.forwardRef((props, ref) => {
    const { form, fieldName, rules, initialValue, columns, disabled, readonly, recordModel, ...otherProps } = props;
    const { list, ...listMethods } = useDynamicList([]);
    const prevFormValuesRef = useRef(form.getFieldsValue()?.[fieldName]);
    const formRef = useRef(form);

    // 宽度综合
    const columnsWidthTotal = useMemo(
        () => columns.filter(item => !item.hide).reduce((total, current) => total + (Number(current.width) || 150), 0),
        [columns]
    );

    const required = useMemo(() => {
        if (otherProps.required !== null && otherProps.required !== undefined) {
            return otherProps.required;
        }
        return otherProps.label && rules && rules.some(item => item.required);
    }, [otherProps.label, otherProps.required, rules]);

    useEffect(() => {
        formRef.current = form;
    }, [form]);

    useEffect(() => {
        const oldSetFieldsValue = form.setFieldsValue;
        // 劫持 setFieldsValue 方法, 使得通过 setFieldsValue 来重置表单的功能得以实现
        form.setFieldsValue = changeData => {
            oldSetFieldsValue(changeData);
            if (changeData.hasOwnProperty(fieldName)) {
                const fromFormValue = changeData[fieldName];
                listMethods.resetList([]);
                setTimeout(() => {
                    listMethods.resetList(fromFormValue ? listMethods.sortForm(fromFormValue) : []);
                });
                prevFormValuesRef.current = fromFormValue;
            }
        };
        return () => {
            form.setFieldsValue = oldSetFieldsValue;
        };
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [form]);

    // 监听 initialValue 变化
    useEffect(() => {
        listMethods.resetList(initialValue || []);
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [JSON.stringify(initialValue)]);

    // 暴露方法
    useImperativeHandle(
        ref,
        () => ({
            methods: listMethods
        }),
        [listMethods]
    );

    return (
        <Form.Item required={required} {...otherProps}>
            {list?.length === 0 &&
                rules &&
                form.getFieldDecorator(`${fieldName}Temp`, { rules, preserve: false })(
                    <input type="text" style={{ display: 'none' }} />
                )}
            <div className={classNames(styles.editableTableWrapper, 'ant-form-inline')}>
                <table className={styles.editableTable} style={{ width: columnsWidthTotal }}>
                    <TableHeader columns={columns} />
                    <tbody className={styles.tableBody}>
                        {list.map((record, index) => {
                            const recordKey = listMethods.getKey(index);
                            return (
                                <TableRow
                                    key={`row-${recordKey}`}
                                    fieldName={fieldName}
                                    recordKey={recordKey}
                                    columns={columns}
                                    index={index}
                                    record={record}
                                    form={formRef.current}
                                    methods={listMethods}
                                    disabled={disabled}
                                    readonly={readonly}
                                />
                            );
                        })}
                    </tbody>
                </table>
            </div>
            {list.length === 0 && <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
            {!disabled && !readonly && (
                <Button className={styles.addButton} type="dashed" block onClick={() => listMethods.push(recordModel)}>
                    <IconPro
                        type="iconadd_function_o"
                        style={{ marginRight: 6, fontSize: 14, color: 'rgb(0 0 0 / 65%)' }}
                    />
                    添加
                </Button>
            )}
        </Form.Item>
    );
});

DynamicTable.propTypes = {
    initialValue: PropTypes.array,
    columns: PropTypes.array.isRequired,
    form: PropTypes.object.isRequired,
    rules: PropTypes.array,
    fieldName: PropTypes.string.isRequired,
    disabled: PropTypes.bool,
    readonly: PropTypes.bool,
    recordModel: PropTypes.object,
    scroll: PropTypes.bool
};
DynamicTable.defaultProps = {
    initialValue: null,
    rules: null,
    disabled: false,
    readonly: false,
    recordModel: {},
    scroll: false
};
DynamicTable.displayName = 'DynamicTable';

export default React.memo(DynamicTable);
